package com.hixtrip.sample.domain.inventory;

import com.hixtrip.sample.domain.inventory.model.Inventory;
import com.hixtrip.sample.domain.inventory.repository.InventoryRepository;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.concurrent.TimeUnit;

/**
 * 库存领域服务
 * 库存设计，忽略仓库、库存品、计量单位等业务
 */
@Component
public class InventoryDomainService {

    @Autowired
    private InventoryRepository inventoryRepository;

    @Autowired
    private RedissonClient redissonClient;


    /**
     * 获取sku当前库存
     *
     * @param skuId
     */
    public Integer getInventory(String skuId) {
        //todo 需要你在infra实现，只需要实现缓存操作, 返回的领域对象自行定义
        Inventory inventory = inventoryRepository.getInventory(skuId);
        return inventory == null ? 0 : inventory.getSellableQuantity().intValue();
    }

    /**
     * 修改库存
     *
     * @param skuId
     * @param sellableQuantity    可售库存
     * @param withholdingQuantity 预占库存
     * @param occupiedQuantity    占用库存
     * @return
     */
    public Boolean changeInventory(String skuId, Long sellableQuantity, Long withholdingQuantity, Long occupiedQuantity) {
        //todo 需要你在infra实现，只需要实现缓存操作。
        // 需要加锁, 再次确认库存量, 保证查询库存和修改库存属于同一个原子操作

        RLock lock = redissonClient.getLock("LOCK:INVENTORY:" + skuId);

        try{
            boolean isLock = lock.tryLock(10, TimeUnit.SECONDS);
            if (!isLock){
                return false;
            }

            Inventory inventory = inventoryRepository.getInventory(skuId);
            if (inventory.getSellableQuantity() < withholdingQuantity){
                return false;
            }
            // 扣减后的库存
            long newSellableQuantity = inventory.getSellableQuantity() - withholdingQuantity;
            // 新的占用库存
            long newOccupiedQuantity = inventory.getOccupiedQuantity() + withholdingQuantity;
            // 扣减库存
            inventoryRepository.changeInventory(skuId, newSellableQuantity, newOccupiedQuantity);
            return true;
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
        return false;
    }
}
